package me.ratel.demo.eBook.infrastructure.utils;

import com.google.common.cache.Cache;
import com.google.common.cache.CacheBuilder;
import com.sun.xml.internal.bind.marshaller.CharacterEscapeHandler;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import javax.xml.bind.JAXBContext;
import javax.xml.bind.JAXBException;
import javax.xml.bind.Marshaller;
import javax.xml.bind.Unmarshaller;
import java.io.InputStream;
import java.io.StringWriter;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.TimeUnit;

/**
 * @author Administrator
 * @time 2016/8/28 15:53
 */
public class XmlUtils {
    private static final Logger log = LoggerFactory.getLogger(XmlUtils.class);

    private static final Cache<Class, Object> cache = CacheBuilder.newBuilder()
            .expireAfterAccess(1, TimeUnit.SECONDS)
            .maximumSize(1000).build();

    public static String toXML(Object obj) {
        StringWriter sw = new StringWriter();
        try {
            ((Marshaller)cache.get(obj.getClass(), () -> {
                Marshaller marshaller;
                try {
                    marshaller = JAXBContext.newInstance(obj.getClass()).createMarshaller();
                    marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);
                    marshaller.setProperty(Marshaller.JAXB_FRAGMENT, true);
                    marshaller.setProperty("com.sun.xml.internal.bind.marshaller.CharacterEscapeHandler",
                            (CharacterEscapeHandler) (ch, start, length, isAttVal, writer) -> writer.write(ch, start, length));
                } catch (JAXBException jaxbe) {
                    throw new IllegalArgumentException(jaxbe);
                }
                return marshaller;
            })).marshal(obj, sw);
        } catch (ExecutionException | JAXBException e) {
            log.error("", e);
            return null;
        }
        return sw.toString();
    }

    public static <E> E toBean(InputStream xml, Class<E> clazz) {
        Object obj;
        try {
            obj = ((Unmarshaller)cache.get(clazz, () -> {
                Unmarshaller unmarshaller;
                {
                    try {
                        unmarshaller = JAXBContext.newInstance(clazz).createUnmarshaller();
                    } catch (JAXBException jaxbe) {
                        throw new IllegalArgumentException(jaxbe);
                    }
                }
                return unmarshaller;
            })).unmarshal(xml);
        } catch (ExecutionException | JAXBException e) {
            log.error("", e);
            return null;
        }
        return (E)obj;
    }
}
